/**********************************************************************************
 * Copyright (c) 2012 - 2012,  quick_tools, All right reserved
 * Title: com.adc.quicktools.net.ftp  FtpUtil.java 
 * @author shen  shenqiao2012@163.com 
 *  2012-6-21 下午4:28:30 
 *********************************************************************************/


package com.adc.quicktools.net.ftp;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;


import com.adc.quicktools.StringUtil;
import com.adc.quicktools.constants.ConstantDefine;
import com.adc.quicktools.file.FileControl;






public class FtpUtil {
	
	/**
	 * 
	 * Description:   动态创建ftp参数信息
	 * author:  shen
	 * @param host  主机
	 * @param port  端口
	 * @param user  用户名
	 * @param password  密码
	 * @param homeDir  主目录
	 * @return Properties  返回含有参数信息的properties
	 */
	public static Properties registFtpServerInfo(String host,int port,String user,String password,String homeDir) {
		Properties properties=null;
		if (StringUtil.checkStringValue(host)&&port>-1 && StringUtil.checkStringValue(user)&&
				StringUtil.checkStringValue(homeDir)) {
			properties=new Properties();
			if (!StringUtil.checkStringValue(password)) {
				user="anonymous";
				password="";
			}
			properties.setProperty(ConstantDefine.FTP_Hostname_KEY, host);
			properties.setProperty(ConstantDefine.FTP_Port_KEY, Integer.toString(port));
			properties.setProperty(ConstantDefine.FTP_User_KEY, user);
			properties.setProperty(ConstantDefine.FTP_Pwd_KEY, password);
			properties.setProperty(ConstantDefine.FTP_Home_KEY, homeDir);
		}
		return properties;
	}

	/**
	 * 
	 * Description: 下载单个文件；
	 * author:  shen
	 * @param ftpInfo ftp相关信息，通过 {@link com.adc.quicktools.net.ftp.FtpUtil#registFtpServerInfo(String, int, String, String, String)}注册ftp相关信息；
	 * @param remoteFilePath 可支持通配符的远程文件全路径
	 * @param localFilePath 本地文件全路径
	 * @return boolean
	 */
	public static boolean downloadOneFileByFTP(Properties ftpInfo,String remoteFilePath,String localFilePath) {
		boolean result=false;
		String exeInfo="";
		if (ftpInfo!=null && !ftpInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(ftpInfo);
			if (ftpClient!=null&&StringUtil.checkStringValue(remoteFilePath)
					&&StringUtil.checkStringValue(localFilePath)) {
				exeInfo=exeInfo.concat("remoteFilePath:"+remoteFilePath+"\nlocalFilePath:"+localFilePath+"\n");
				try {
					remoteFilePath=remoteFilePath.replace("\\", "/");
					FTPFile[] ftpFiles=ftpClient.listFiles(remoteFilePath);
					if (ftpFiles!=null&&ftpFiles.length==1) {
						String remoteParentPath=remoteFilePath.substring(0,remoteFilePath.lastIndexOf("/")+1);
						InputStream in =ftpClient.retrieveFileStream(remoteParentPath+ftpFiles[0].getName());  // 直接使用时，带通配符的无法实现；
						OutputStream out = new BufferedOutputStream(new FileOutputStream(localFilePath));
						if (in!=null && out!=null) {
							System.out.println("Start download...");
							result = FileControl.writeOrReadAsStream(in, out);
						}else {
							exeInfo=exeInfo.concat("Can not find RemoteFile Or LocalFile is not exist!\n");
						}
					}else {
						exeInfo=exeInfo.concat("File Counts["+ftpFiles.length+
								"] not equal 1, please use another method or check " +
								"your Parameter[remoteFilePath]!");
					}
					exeInfo=exeInfo.concat("Result is["+result+"]!\n");
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
					System.out.println("\tExecution Infomation:\n"+exeInfo);
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 根据文件全路径匹配，下载到指定文件夹下；
	 * author:  shen
	 * @param ftpInfo ftp信息
	 * @param remoteFilePath  远程文件的父路径
	 * @param matchedName 含有通配符的文件名关键字
	 * @param localDir 指定的本地文件夹
	 * @return List<String>
	 */
	public static List<String> downloadMultFileByFTP(Properties ftpInfo,String remoteFileParentPath,String matchedName,String localDir) {
		List<String> result=null;
		String exeInfo="";
		if (ftpInfo!=null && !ftpInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(ftpInfo);
			if (ftpClient!=null&&StringUtil.checkStringValue(remoteFileParentPath)
					&&StringUtil.checkStringValue(localDir)&&new File(localDir).isDirectory()) {
				remoteFileParentPath=FileControl.checkDirEndWith(remoteFileParentPath).replace("\\", "/");
				try {
					result=new ArrayList<String>();
					String remoteFilePath=remoteFileParentPath.concat(matchedName);
					FTPFile[] ftpFiles=ftpClient.listFiles(remoteFilePath);
					System.out.println("Start download...");
					OutputStream out=null;
					if (ftpClient.changeWorkingDirectory(remoteFileParentPath)) {
						for (int i=0;i<ftpFiles.length;i++) {
							exeInfo=exeInfo.concat("\tThe Status of FTPClient:["+ftpClient.isConnected()+"]\n");
							boolean b=false;
							String fileName=ftpFiles[i].getName();
							String localFilePath=FileControl.checkDirEndWith(localDir).replace("\\", "/").concat(fileName);
							String realRemoteFilePath=remoteFileParentPath.concat(ftpFiles[i].getName());
							out = new FileOutputStream(localFilePath);
							if (out!=null) {
								b = ftpClient.retrieveFile(fileName, out);
								if (b) {
									result.add(localFilePath);
								}
							}
							exeInfo=exeInfo.concat("\tFile[count:"+(i+1)+"] remote["+realRemoteFilePath+"] to ["+localFilePath+"],Result is ["+b+"]\n\n");
						}
					}else {
						exeInfo=exeInfo.concat("\tCan not find RemoteFileParentPath["+remoteFileParentPath+"]!\n");
					}
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
					System.out.println("\tExecution Infomation:\n"+exeInfo);
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 上传单个文件到FTP server
	 * author:  shen
	 * @param hostInfo
	 * @param remoteFilePath
	 * @param localFilePath
	 * @return boolean
	 */
	public static boolean uploadOneFileByFTP(Properties hostInfo,String remoteFilePath,String localFilePath) {
		boolean result=false;
		String exeInfo="";
		if (hostInfo!=null && !hostInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(hostInfo);
			if (ftpClient!=null&&StringUtil.checkStringValue(remoteFilePath)
					&&StringUtil.checkStringValue(localFilePath)&& new File(localFilePath).isFile()) {
				exeInfo=exeInfo.concat("\tremoteFilePath:"+remoteFilePath+"\n\tlocalFilePath:"+localFilePath+"\n");
				try {
					remoteFilePath=remoteFilePath.replace("\\", "/");
					localFilePath=localFilePath.replace("\\", "/");
					exeInfo=exeInfo.concat("\tCreate ParentPath:"+ensureParentPathByFTP(ftpClient, remoteFilePath)+"\n");
					String remoteParentPath=remoteFilePath.substring(0,remoteFilePath.lastIndexOf("/")+1);
					String fileName=remoteFilePath.substring(remoteFilePath.lastIndexOf("/")+1, remoteFilePath.length());
					if (ftpClient.changeWorkingDirectory(remoteParentPath)) {
						InputStream in =new FileInputStream(localFilePath);
						if (in!=null ) {
							System.out.println("Start upload...\n\tFileName["+fileName+"]");
							result = ftpClient.storeFile(fileName, in);
						}
						exeInfo=exeInfo.concat("\tResult is["+result+"]!\n");
					}else {
						exeInfo=exeInfo.concat("\tCannot change dir to["+remoteParentPath+"]!\n");
					}
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
					System.out.println("\tExecution Infomation:\n"+exeInfo);
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 删除指定的ftp路径，可以是文件，可以是目录；
	 * author:  shen
	 * @param hostInfo
	 * @param remoteFilePath 可以是文件，也可以是是路径，是路径时，请去掉尾部的“/”
	 * @return boolean
	 */
	public static boolean deleteByFtp(Properties hostInfo,String remoteFilePath) {
		boolean result=false;
		boolean hasFail=false;
		String exeInfo="";
		if (hostInfo!=null && !hostInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(hostInfo);
			if (ftpClient!=null&&StringUtil.checkStringValue(remoteFilePath)) {
				try {
					remoteFilePath=remoteFilePath.replace("\\", "/");
					String remoteFileParentPath=remoteFilePath.substring(0,remoteFilePath.lastIndexOf("/")+1);
					String tempName=new File(remoteFilePath).getName();
					ftpClient.changeWorkingDirectory(remoteFileParentPath);
					FTPFile[] files=ftpClient.listFiles();
					System.out.println("Start Delete...");
					for (int i = 0; i < files.length; i++) {
						boolean b=false;
						String fileName=files[i].getName();
						if (tempName.equals(fileName)) {
							if (files[i].isFile()) {
								b=ftpClient.deleteFile(remoteFileParentPath+fileName);
								exeInfo=exeInfo.concat("\tCount["+(i+1)+"] : \tDelete File ["+fileName+"] result ["+b+"]\n");
							}else if (files[i].isDirectory()) {
								b=recursivelyDeleteFolders(ftpClient, files[i], remoteFileParentPath+fileName);
								exeInfo=exeInfo.concat("\tCount["+(i+1)+"] : \tDelete Directory ["+fileName+"] result ["+b+"]\n");
							}
							if (!b) {
								hasFail=true;
							}
						}
					}
					if (!hasFail) {
						result=true;
					}
					exeInfo=exeInfo.concat("\tDelete [remoteFilePath:"+remoteFilePath+"] result is ["+result+"]\n");
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
					System.out.println("\tExecution Infomation:\n"+exeInfo);
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 递归删除指定的ftp文件夹及其下的所有文件、文件夹；
	 * author:  shen
	 * @param ftpClient
	 * @param folder 
	 * @param folderPath
	 * @return boolean
	 */
	private static boolean recursivelyDeleteFolders(FTPClient ftpClient,FTPFile folder,String folderPath) {
		boolean result=false;
		if (ftpClient!=null&&folder!=null&&folder.isDirectory()) {
			try {
				System.out.println("starting recursively Delete Folders...");
				ftpClient.changeWorkingDirectory(folderPath);
				FTPFile[] files=ftpClient.listFiles();
				for (int i = 0; i < files.length; i++) {
					String nameString=files[i].getName();
					String pathNameString=folderPath.concat("/"+nameString);
					if (files[i].isFile()) {
						System.out.println("[RDF]Delete File["+nameString+"]:"+ftpClient.deleteFile(pathNameString));
					}else if(files[i].isDirectory()){
						System.out.println("Recursive Operation Result:"+recursivelyDeleteFolders(ftpClient, files[i], pathNameString));
					}
				}
				result=ftpClient.removeDirectory(folderPath);
				System.out.println("[RDF]Remove Directory["+folderPath+"],Result is["+result+"]");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 将同一个ftp目录上指定文件，移动到另一个路径下，同时可以进行重命名；
	 * author:  shen
	 * @param hostInfo
	 * @param oldNamePath
	 * @param newNamePath
	 * @return boolean
	 */
	public static boolean renameByFtp(Properties hostInfo,String oldNamePath,String newNamePath) {
		boolean result=false;
		String exeInfo="";
		if (hostInfo!=null && !hostInfo.isEmpty()&&StringUtil.checkStringValue(oldNamePath)
				&&StringUtil.checkStringValue(newNamePath)) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(hostInfo);
			if (ftpClient!=null) {
				exeInfo=exeInfo.concat("\toldNamePath:"+oldNamePath+"\n\tnewNamePath:"+newNamePath+"\n");
				try {
					oldNamePath=oldNamePath.replace("\\", "/");
					newNamePath=newNamePath.replace("\\", "/");
					exeInfo=exeInfo.concat("\tCreate ParentPath:"+ensureParentPathByFTP(ftpClient, newNamePath)+"\n");
					String oldRemoteParentPath=oldNamePath.substring(0,oldNamePath.lastIndexOf("/")+1);
					String fileName=oldNamePath.substring(oldNamePath.lastIndexOf("/")+1, oldNamePath.length());
					if (ftpClient.changeWorkingDirectory(oldRemoteParentPath)) {
						result=ftpClient.rename(fileName, newNamePath);
						exeInfo=exeInfo.concat("\tResult is["+result+"]!\n");
					}else {
						exeInfo=exeInfo.concat("\tCannot change dir to["+oldRemoteParentPath+"]!\n");
					}
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
					System.out.println("\tExecution Infomation:\n"+exeInfo);
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 列出指定目录下的文件列表
	 * author:  shen
	 * @param ftpInfo
	 * @param filePath
	 * @return List<String>
	 */
	public static List<String> getNameList(Properties ftpInfo, String filePath) {
		List<String> nameList=null;
		if (ftpInfo!=null&&!ftpInfo.isEmpty()&&StringUtil.checkStringValue(filePath)) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(ftpInfo);
			if (ftpClient!=null) {
				nameList=new ArrayList<String>();
				filePath=filePath.replace("\\", "/");
				try {
					FTPFile[] names=ftpClient.listFiles(filePath);
					for (FTPFile ftpFile : names) {
						nameList.add(ftpFile.getName());
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return nameList;
	}
	
	/**
	 * 
	 * Description: 列出指定目录下的文件列表
	 * author:  shen
	 * @param ftpInfo
	 * @param filePath
	 * @return List<String>
	 */
	private static List<String> getNameList(FTPClient ftpClient, String filePath) {
		List<String> nameList=null;
		if (ftpClient!=null&&StringUtil.checkStringValue(filePath)) {
				nameList=new ArrayList<String>();
				filePath=filePath.replace("\\", "/");
				try {
					FTPFile[] names=ftpClient.listFiles(filePath);
					for (FTPFile ftpFile : names) {
						nameList.add(ftpFile.getName());
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		return nameList;
	}
	
	/**
	 * 
	 * Description:  保证ftp上某文件的父路径存在
	 * author:  shen
	 * @param ftpInfo 
	 * @param filePath 文件全路径
	 * @return boolean
	 */
	public static boolean ensureParentPathByFTP(Properties ftpInfo, String filePath) {
		String fileParentPath=new File(filePath).getParent();
		if (makeDirectoryByFTP(ftpInfo, fileParentPath)) {
			return true;
		}else {
			String[] str=new String[4];
			File file=new File(fileParentPath);
//			str=file.getParent().split(File.separator);
			if (file.getPath().contains("\\")) {
				String string=fileParentPath;
				string=string.replace("\\", "/");
//				System.out.println(string);
				str=string.split("/");
			}else {
				str=file.getParent().split("/");
			}
			String tempString=str[0];
			for (int j = 1; j < str.length; j++) {
				tempString=tempString.concat("/"+str[j]);
				if (!ftpDirIsExist(ftpInfo, tempString)) {
					makeDirectoryByFTP(ftpInfo, tempString);
				}
			}
			return ftpDirIsExist(ftpInfo, fileParentPath);
		}
	}
	
	/**
	 * 
	 * Description:  保证ftp上某文件的父路径存在
	 * author:  shen
	 * @param ftpClient 
	 * @param filePath 文件全路径
	 * @return boolean
	 */
	private static boolean ensureParentPathByFTP(FTPClient ftpClient, String filePath) {
		String fileParentPath=new File(filePath).getParent();
		if (!ftpDirIsExist(ftpClient, fileParentPath)) {
			String[] str=new String[4];
			File file=new File(fileParentPath);
//			str=file.getParent().split(File.separator);
			str=file.getPath().replace("\\", "/").split("/");
//			if (file.getPath().contains("\\")) {
//				String string=fileParentPath;
//				string=string.replace("\\", "/");
////				System.out.println(string);
//				str=string.split("/");
//			}else {
//				str=file.getPath().split("/");
//			}
			String tempString=str[0];
			for (int j = 1; j < str.length; j++) {
				tempString=tempString.concat("/"+str[j]);
				if (!ftpDirIsExist(ftpClient, tempString)) {
					makeDirectoryByFTP(ftpClient, tempString);
				}
			}
		}
		return ftpDirIsExist(ftpClient, fileParentPath);
	}
	
	/**
	 * 
	 * Description: 判断ftp路径是否存在
	 * author:  shen
	 * @param ftpInfo
	 * @param ftpDir  
	 * @return boolean
	 */
	public static boolean ftpDirIsExist(Properties ftpInfo,String ftpDir) {
		boolean result=false;
		if (ftpInfo!=null && !ftpInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(ftpInfo);
			if (ftpClient!=null) {
				try {
					result=ftpClient.changeWorkingDirectory(ftpDir);
				} catch (IOException e) {
					e.printStackTrace();
				}finally{
					try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 判断ftp路径是否存在
	 * author:  shen
	 * @param ftpClient
	 * @param ftpDir  
	 * @return boolean
	 */
	private static boolean ftpDirIsExist(FTPClient ftpClient,String ftpDir) {
		boolean result=false;
			if (ftpClient!=null&& ftpClient.isConnected()) {
				try {
					result=ftpClient.changeWorkingDirectory(ftpDir);
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 在指定的ftp上创建目录,创建单级目录
	 * author:  shen
	 * @param ftpInfo ftp信息，在properties里
	 * @param filePath 文件路径
	 * @return boolean
	 */
	public static boolean makeDirectoryByFTP(Properties ftpInfo,String filePath) {
		boolean result=false;
		if (ftpInfo!=null && !ftpInfo.isEmpty()) {
			FTPClient ftpClient=new FTPClient();
			ftpClient=getFtpClient(ftpInfo);
            if (ftpClient!=null) {
            	try {
                    result = ftpClient.makeDirectory(filePath.replace("\\", "/"));
                    if (result) {
                        System.out.println("make Directory " +filePath +" succeed");
                    } else {
                        System.out.println("make Directory " +filePath+ " false");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                	try {
						ftpClient.disconnect();
					} catch (IOException e) {
						e.printStackTrace();
					}
                }
			}
		}
		return result;
	}
	
	/**
	 * 
	 * Description: 在指定的ftp上创建目录
	 * author:  shen
	 * @param ftpClient ftp下载链接
	 * @param filePath 文件路径
	 * @return boolean
	 */
	private static boolean makeDirectoryByFTP(FTPClient ftpClient,String filePath) {
		boolean result=false;
		if (ftpClient!=null && ftpClient.isConnected()) {
            	try {
                    result = ftpClient.makeDirectory(filePath.replace("\\", "/"));
                    if (result) {
                        System.out.println("make Directory " +filePath +" succeed");
                    } else {
                        System.out.println("make Directory " +filePath+ " false");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
		}
		return result;
	}
	
	/**
     * 设置FTP客服端的配置--一般可以不设置
     *
     * @return
     */
    private static FTPClientConfig getFtpConfig() {
        FTPClientConfig ftpConfig = new FTPClientConfig(
                FTPClientConfig.SYST_UNIX);
        ftpConfig.setServerLanguageCode(FTP.DEFAULT_CONTROL_ENCODING);
        return ftpConfig;
    }
    
    /**
     * 
     * Description:  根据ftp信息获取ftpclient
     * author:  shen
     * @param ftpInfo  
     * @return FTPClient
     */
    private static FTPClient getFtpClient(Properties ftpInfo){
    	FTPClient ftpClient=null;
    	if (ftpInfo!=null && !ftpInfo.isEmpty()) {
			ftpClient=new FTPClient();
			int reply;
            try {
            	ftpClient.setControlEncoding("GBK");
            	ftpClient.setDefaultPort(Integer.parseInt((String) ftpInfo.get(ConstantDefine.FTP_Port_KEY)));
            	ftpClient.configure(getFtpConfig());
            	ftpClient.connect((String)ftpInfo.get(ConstantDefine.FTP_Hostname_KEY));
            	ftpClient.login((String)ftpInfo.get(ConstantDefine.FTP_User_KEY),
            			(String)ftpInfo.get(ConstantDefine.FTP_Pwd_KEY));
                reply = ftpClient.getReplyCode();
                ftpClient.setDataTimeout(120000);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);   //  二进制传输
                ftpClient.enterLocalPassiveMode();   //  被动模式
                ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);   //  设置文件流传输模式
                if (!FTPReply.isPositiveCompletion(reply)) {
                	ftpClient.disconnect();
                    System.out.println("FTP server refused connection.");
                }
               
            } catch (SocketException e) {
                e.printStackTrace();
                System.out.println("登录ftp服务器【" +ftpInfo.get(ConstantDefine.FTP_Hostname_KEY)+ "】失败,连接超时！" );
            } catch (IOException e) {

                e.printStackTrace();
                System.out.println("登录ftp服务器【"+ ftpInfo.get(ConstantDefine.FTP_Hostname_KEY) +"】失败，FTP服务器无法打开！");
            }
    	}
    	return ftpClient;
    }
	

	
}
